/**
 * Definition of the Printer class
 */
package org.cholm.drtest;
import java.io.PrintStream;
import java.util.Collection;
import java.util.Map;
import java.util.Set;

import org.cholm.drtest.proxy.MediaMetaData;
import org.cholm.drtest.proxy.WebImage;
/**
 * A class to print the information
 *
 * @author cholm
 */
public class Printer {
	/** Show details */
	public static final int SHOW_DETAILS = 0x1;
	/** Show series */
	public static final int SHOW_SERIES  = 0x2;
	/** Show videos */
	public static final int SHOW_VIDEOS  = 0x4;
	/** Show streams */
	public static final int SHOW_STREAMS = 0x8;
	/** Show meta information */
	public static final int SHOW_META    = 0x10;
	/** Show letter */
	public static final int SHOW_LETTER  = 0x20;
	public static final int DEFAULT = SHOW_DETAILS|SHOW_SERIES|SHOW_VIDEOS|SHOW_STREAMS;
	/**
	 * Constructor
	 */
	public Printer() {

	}
	/**
	 * Start a grouping
	 *
	 * @param header What to pring
	 */
	public void begin(String header)
	{
		out.println(ind + header);
		incr();
		sCnt = 0;
		vCnt = 0;
	}
	/**
	 * End of grouping
	 *
	 * @param footer What to print
	 */
	public void end(String footer)
	{
		decr();
		out.println(footer + "(" + sCnt + " series " + vCnt + " videos)");
	}
	/**
	 * Print a mapping
	 *
	 * @param map  Mapping
	 * @param opts Options
	 */
	public void print(Extractor.Mapping map, int opts) {
		for (String key : map.keys()) {
			out.println(ind + key);
			incr();
			print(map.get(key), opts);
			decr();
		}
	}
	/**
	 * Print a map of series
	 *
	 * @param series Map
	 * @param opts   Optios
	 */
	public void print(Map<String,Serie> series, int opts) {
		print(series.values(), opts);
	}
	/**
	 * Print a collection of series
	 *
	 * @param series Collection
	 * @param opts   Options;
	 */
	public void print(Collection<Serie> series, int opts) {
		char old = '\0';
		boolean first = true;
		for (Serie s: series) {
			if (testOpt(opts, SHOW_LETTER)) {
				char u = Character.toUpperCase(s.getLetter().charAt(0));
				if (u != old) {
					if (first) first = false;
					else       decr();
					out.println(ind + u);
					old = u;
					incr();
				}
			}
			print(s, opts);
		}
		if (testOpt(opts, SHOW_LETTER)) decr();
	}
	/**
	 * Print a Serie object
	 *
	 * @param s    Object
	 * @param opts Options
	 */
	public void print(Serie s, int opts) {
		sCnt++;
		out.println(ind + s.slug);
		if (testOpt(opts, SHOW_DETAILS)) {
			incr();
			out.println(ind + "Title:   " + s.getTitle() + "\n" +
						ind + "URL:     " + s.getUrl() + "\n" +
						ind + "Genre:   " + s.getGenre() + "\n" +
						ind + "Channel: " + s.getChannel());
		}
		if ((opts & SHOW_VIDEOS) != 0) {
			incr();
			for (Program v : s.getVideos()) print(v, opts);
			decr();
		}
		if (testOpt(opts, SHOW_DETAILS)) decr();
	}
	/**
	 * Print a video object
	 *
	 * @param v    Object
	 * @param opts Options
	 */
	public void print(Program v, int opts) {
		vCnt++;
		out.println(ind + v.getId());
		if (testOpt(opts, SHOW_DETAILS)) {
			incr();
			out.println(ind + "Title: " + v.getTitle() + "\n" +
					    ind + "Date:  " + v.getDate());
		}
		if ((opts & SHOW_STREAMS) != 0) {
			incr();
			for (int i = Program.LOW; i <= Program.HIGH; i++)
				out.println(ind + (i == Program.LOW    ? "low:    " :
								   i == Program.MEDIUM ? "medium: " :
								   i == Program.HIGH   ? "high:   " : "?: ") +
					               v.getStream(i));
			decr();
		}
		if (testOpt(opts, SHOW_DETAILS)) decr();
	}
	/**
	 * Print meta data
	 *
	 * @param m     Meta data
	 * @param opts  Options
	 */
	public void print(MediaMetaData m, int opts) {
		Set<String> keys = m.keySet();
		int max = 0;
		for (String k : keys) {
			max = Math.max(k.length(), max);
		}
		String format = ind + "%-" + max + "s: %s";
		for (String k : keys) {
			out.printf(format, k, m.getString(k));
		}
		if (testOpt(opts, SHOW_DETAILS) && m.getImages().size() > 0) {
			out.println("Images:");
			incr();
			for (WebImage w : m.getImages()) {
				print(w, opts);
			}
			decr();
		}
	}
	/**
	 * Print a web-image
	 *
	 * @param w     Object
	 * @param opts  Options;
	 */
	public void print(WebImage w, int opts) {
		out.println(ind + w.getUrl() +
				    "(" + w.getWidth() + "x" + w.getHeight() + ")");
	}
	/**
	 * Increment indention
	 */
	protected void incr() { ind += " "; }
	/**
	 * Decrement indention
	 */
	protected void decr() { ind = ind.substring(0, ind.length()-1); }
	/**
	 * Test an option
	 *
	 * @param opt   Bit-pattern of options
	 * @param flag  Bit-pattern to test against
	 *
	 * @return true if flag is set in opt
	 */
	protected boolean testOpt(int opt, int flag)  {
		return (opt & flag) != 0;
	}
	/**
	 * The output stream
	 */
	private PrintStream out = System.out;
	/**
	 * Current indention
	 */
	private String ind = "";
	/**
	 * Count of series
	 */
	protected int sCnt = 0;
	/**
	 * Count of program instances
	 */
	protected int vCnt = 0;

}

/* EOF */